package com.wyix.state;


import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 线程状态转换模拟：餐厅厨师工作流程
 * 展示线程的6种状态：New -> Runnable -> Blocked -> Waiting -> Timed Waiting -> Terminated
 */
public class ChefThreadStateSimulation {
    // 食材锁（模拟资源竞争）
    private static final Lock ingredientLock = new ReentrantLock();
    // 订单通知器（模拟等待/唤醒机制）
    private static final Object orderNotifier = new Object();
    // 餐厅是否营业
    private static volatile boolean restaurantOpen = true;

    public static void main(String[] args) throws InterruptedException {
        System.out.println("===== 餐厅厨房线程状态模拟开始 =====");
        System.out.println("提示：状态说明 - NEW(新订单)、RUNNABLE(烹饪中)、BLOCKED(等食材)、WAITING(等订单)、TIMED_WAITING(休息中)、TERMINATED(下班)");

        // 创建厨师线程（初始状态：NEW）
        ChefThread chefZhang = new ChefThread("张厨师", "红烧肉");
        ChefThread chefLi = new ChefThread("李厨师", "清蒸鱼");

        printThreadState(chefZhang, "创建后");
        printThreadState(chefLi, "创建后");

        // 启动线程（状态变为：RUNNABLE）
        System.out.println("\n=== 开始营业，厨师们准备工作 ===");
        chefZhang.start();
        chefLi.start();

        // 观察初始状态
        Thread.sleep(500);
        printThreadState(chefZhang, "启动后");
        printThreadState(chefLi, "启动后");

        // 模拟业务流程：运行3秒后发布紧急订单
        Thread.sleep(3000);
        System.out.println("\n=== 收到VIP订单，唤醒等待中的厨师 ===");
        synchronized (orderNotifier) {
            orderNotifier.notifyAll(); // 唤醒所有等待的厨师
        }

        // 运行5秒后结束营业
        Thread.sleep(5000);
        System.out.println("\n=== 餐厅打烊，停止接受新订单 ===");
        restaurantOpen = false;

        // 等待所有厨师完成工作
        chefZhang.join();
        chefLi.join();
        System.out.println("\n===== 餐厅厨房线程状态模拟结束 =====");

    }

    /**
     * 厨师线程类
     */
    static class ChefThread extends Thread {
        private final String chefName;
        private final String dishName;
        private final Random random = new Random();

        public ChefThread(String chefName, String dishName) {
            super(chefName);
            this.chefName = chefName;
            this.dishName = dishName;
        }

        @Override
        public void run() {
            try {
                // 1. 准备阶段（RUNNABLE）
                System.out.printf("%s: 开始准备%s的食材...\n", chefName, dishName);
                work(1000); // 模拟准备食材时间

                // 2. 获取食材锁（可能进入BLOCKED状态）
                System.out.printf("%s: 尝试获取食材...\n", chefName);
                ingredientLock.lock();
                try {
                    System.out.printf("%s: 成功获取食材，开始烹饪%s...\n", chefName, dishName);
                    work(2000); // 模拟烹饪时间
                } finally {
                    ingredientLock.unlock(); // 释放锁
                    System.out.printf("%s: 释放食材资源\n", chefName);
                }

                // 3. 等待新订单（进入WAITING状态）
                if (restaurantOpen) {
                    System.out.printf("%s: 等待新订单...\n", chefName);
                    synchronized (orderNotifier) {
                        orderNotifier.wait(); // 等待通知
                    }
                    System.out.printf("%s: 收到新订单通知！\n", chefName);
                    work(1500); // 处理新订单
                }

                // 4. 定时休息（进入TIMED_WAITING状态）
                if (restaurantOpen) {
                    System.out.printf("%s: 太累了，休息3秒...\n", chefName);
                    Thread.sleep(3000); // 定时等待
                }

                // 5. 完成工作（状态变为TERMINATED）
                System.out.printf("%s: %s制作完成，下班！\n", chefName, dishName);

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.out.printf("%s: 工作被中断！\n", chefName);
            }
        }

        /**
         * 模拟工作时间
         */
        private void work(int millis) throws InterruptedException {
            int interval = Math.min(500, millis);
            int rounds = millis / interval;
            for (int i = 0; i < rounds; i++) {
                Thread.sleep(interval);
                System.out.printf("%s: 工作中... %d%%\r", chefName, (i + 1) * 100 / rounds);
            }
            System.out.println();
        }
    }

    /**
     * 打印线程状态
     */
    private static void printThreadState(Thread thread, String stage) {
        System.out.printf("线程状态 [%s-%s]: %s\n",
                thread.getName(), stage, thread.getState());
    }
}